<!-- Copyright (C) 2019-2021 Junruoyu Zheng. Home page: https://junruoyu-zheng.gitee.io/ligral

     Distributed under MIT license.
     See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
-->
<!DOCTYPE html>
<html lang="en">
 <head>
  <title>
   语法设计
  </title>
  <meta charset="utf-8"/>
  <meta content="width=device-width, initial-scale=1, shrink-to-fit=no" name="viewport"/>
  <!-- Main CSS -->
  <link href="/ligral/css/style.css" rel="stylesheet"/>
  <link href="/ligral/css/rolling.css" rel="stylesheet"/>
  <link href="/ligral/css/custom.css" rel="stylesheet"/>
  <link href="/ligral/css/katex.min.css" rel="stylesheet"/>
  <link href="/ligral/avatar.png" rel="shortcut icon" type="image/x-icon"/>
  <!-- Font Awesome -->
  <script crossorigin="anonymous" src="https://kit.fontawesome.com/14294c79e2.js">
  </script>
 </head>
 <body>
  <!-- Header -->
  <div class="header-wrap d-none d-md-block">
   <div class="container">
    <div class="row">
     <!-- Left header box -->
     <header class="col-6 text-left">
      <h1 class="letter-wrap title">
       Ligral
      </h1>
     </header>
    </div>
   </div>
  </div>
  <!-- Main navigation -->
  <nav class="navbar navbar-expand-md navbar-dark bg-primary">
   <div class="container">
    <!-- Company name shown on mobile -->
    <a class="navbar-brand d-md-none d-lg-none d-xl-none" href="#">
     Ligral
    </a>
    <!-- Mobile menu toggle -->
    <button aria-controls="mainNavbar" aria-expanded="false" aria-label="Toggle navigation" class="navbar-toggler" data-target="#mainNavbar" data-toggle="collapse" type="button">
     <span class="navbar-toggler-icon">
     </span>
    </button>
    <!-- Main navigation items -->
    <div class="collapse navbar-collapse" id="mainNavbar">
     <ul class="navbar-nav mr-auto">
      <li class="nav-item">
       <a class="nav-link" href="/ligral/index.html">
        主页
        <span class="sr-only">
         (current)
        </span>
       </a>
      </li>
      <li class="nav-item dropdown active">
       <a aria-expanded="false" aria-haspopup="true" class="nav-link dropdown-toggle" data-toggle="dropdown" href="#" role="button">
        文档
       </a>
       <div class="dropdown-menu navbar-dark bg-primary">
        <a class="dropdown-item" href="/ligral/quick-start.html">
         快速开始
        </a>
        <a class="dropdown-item" href="/ligral/user-guide">
         用户文档
        </a>
        <a class="dropdown-item" href="/ligral/dev-guide">
         开发文档
        </a>
        <a class="dropdown-item" href="/ligral/interface/">
         接口定义
        </a>
       </div>
      </li>
      <!-- <li class="nav-item">
                                <a class="nav-link" href="#">Services</a>
                        </li> -->
      <li class="nav-item">
       <a class="nav-link" href="/ligral/product.html">
        产品
       </a>
      </li>
      <li class="nav-item">
       <a class="nav-link" href="/ligral/contact.html">
        联系我们
       </a>
      </li>
     </ul>
     <!-- <form class="form-inline header-search-form my-2 my-lg-0">
                        <input class="form-control mr-sm-2" type="text" size="10"  placeholder="Search" aria-label="Search">
                        <button class="btn btn-secondary my-2 my-sm-0" type="submit">Search</button>
                    </form> -->
    </div>
   </div>
  </nav>
  <!-- Jumbtron / Slider -->
  <!-- Main content area -->
  <main class="container">
   <div class="row" style="flex-direction: row-reverse;">
    <!-- Main content -->
    <div class="col-sm-8">
     <article>
      <h1>
       语法设计
      </h1>
      <p>
       在用户文档你可能已经了解过 Ligral 的语法，但你可能不明白我为什么要这么设计，因为 Ligral 有许多非常新鲜的、独特的语法。这篇文章就来讲讲我设计 Ligral 的思路，以便让你们更快地融入开发者这一角色。
      </p>
      <p>
       语法设计是 Ligral 的源动力，因为 Ligral 的诞生就是为了解决在搭建仿真模型时使用 Simulink 的槽点。
      </p>
      <p>
       实现一个基于文本语言的仿真程序有很多种实现方式，比如可以用 C++ 编写。事实上只要你实现了
       <span class="katex">
        <span class="katex-mathml">
         <math xmlns="http://www.w3.org/1998/Math/MathML">
          <semantics>
           <mrow>
            <mi>
             f
            </mi>
            <mo stretchy="false">
             (
            </mo>
            <mi>
             x
            </mi>
            <mo separator="true">
             ,
            </mo>
            <mi>
             u
            </mi>
            <mo separator="true">
             ,
            </mo>
            <mi>
             t
            </mi>
            <mo stretchy="false">
             )
            </mo>
           </mrow>
           <annotation encoding="application/x-tex">
            f(x,u,t)
           </annotation>
          </semantics>
         </math>
        </span>
        <span aria-hidden="true" class="katex-html">
         <span class="base">
          <span class="strut" style="height:1em;vertical-align:-0.25em;">
          </span>
          <span class="mord mathnormal" style="margin-right:0.10764em;">
           f
          </span>
          <span class="mopen">
           (
          </span>
          <span class="mord mathnormal">
           x
          </span>
          <span class="mpunct">
           ,
          </span>
          <span class="mspace" style="margin-right:0.16666666666666666em;">
          </span>
          <span class="mord mathnormal">
           u
          </span>
          <span class="mpunct">
           ,
          </span>
          <span class="mspace" style="margin-right:0.16666666666666666em;">
          </span>
          <span class="mord mathnormal">
           t
          </span>
          <span class="mclose">
           )
          </span>
         </span>
        </span>
       </span>
       这个函数，调用求解器求解，就是一个仿真程序了。但是为什么大家都用 Simulink 来生成代码，而不是自己手动写呢？答案就是为了方便、直观。C++、Python 等语言不是为了仿真而设计的，这些语言功能固然强大，但是代价就是使用起来也较为繁琐，需要自己处理很多细节。一个假想的 python 程序如下所示：
      </p>
      <pre><code>def f(x, u, t):
    return 1

solver = Solver()
solver.config(...)
solver.solve(f, lambda x: x)
x, y, t = solver.results

# 处理 x 和 y，比如绘图
</code></pre>
      <p>
       如果你将 Simulink 工程保存为
       <code>
        .mdl
       </code>
       文件，你可以用文本编辑器打开。实际上我们可以称这个文本文件里的代码为一种“MDL”语言，它和你在 Simulink 界面上看到的图形是完全等效的。MDL 语言和 Ligral 语言类似，是一种描述性的语言，也具有很多 C++ 这类命令式的语言所不具备的优点，比如无需考虑实现的细节。它的语法大致如下：
      </p>
      <pre><code>Model {
    StartTime         "0.0"
    StopTime          "100"
    ...
    System {
        Block {
            BlockType         Constant
            Name              "Constant1"
            Value              "1"
            ...
        }
        Block {
            BlockType         Integrator
            Name              "Integrator1"
        }
        Line {
            SrcBlock              "Constant1"
            SrcPort               1
            DstBlock              "Integrator1"
            DstPort               1
            ...
        }
    }
}
</code></pre>
      <p>
       可以看到这是一种非常典型的声明语法，它首先描述了一些设置项，然后声明了所使用的模块，最后再定义了模块之间的连接。与之相似的，Ligral 开放给第三方的接口格式
       <code>
        .lig.json
       </code>
       也采用了类似的语法：
      </p>
      <pre><code>{
    "settings": [
        {
            "item": "step_size",
            "value": 0.1
        },
        {
            "item": "stop_time",
            "value": 10
        }
    ],
    "models": [
        {
            "id": "Constant1",
            "type": "Constant",
            "parameters": [
                {
                    "name": "value",
                    "value": 1
                }
            ],
            "out-ports": [
                {
                    "name": "value",
                    "destination": [
                        {
                            "id": "Integrator1",
                            "in-port": "input"
                        }
                    ]
                }
            ]
        },
        {
            "id": "Integrator1",
            "type": "Integrator",
            "parameters": [],
            "out-ports": []
        }
    ]
}
</code></pre>
      <p>
       可是这样的文本仿真语言，比起图形语言真的有任何优势吗？从直观角度而言，它们差得远了；从编写的容易程度而言，Simulink 中你只要拖放两个模块，然后将它们连起来，这些文本语言却要写这么多，甚至还不如命令式的语言，真是令人望而生畏！说服 Simulink 用户去使用这样的语言是不现实的。但如果你使用 Ligral，只需要下面一行语句：
      </p>
      <pre><code>1 -&gt; Integrator;
</code></pre>
      <p>
       把枯燥的、重复的工作交给解释器，用户只要把握住最核心的框图，就能写出一个仿真程序。
      </p>
      <p>
       <strong>
        因此，Ligral 语法设计从一开始就聚焦在如何方便用户。
       </strong>
      </p>
      <h3>
       调用时声明
      </h3>
      <p>
       常见的命令式语言中，声明语句和调用语句是分开的。如果需要在多处调用一个节点，必须声明一个标识符，伪码如下：
      </p>
      <pre><code>constant1 = Constant(1)
constant1.connect(node1)
constant1.connect(node2)
</code></pre>
      <p>
       而在 Ligral 中，声明和调用允许同时进行。为了实现这一点，Ligral 放弃了常见的
       <code>
        =
       </code>
       号赋值这一做法，而采用了用一对
       <code>
        [ ]
       </code>
       来命名。
      </p>
      <pre><code>Constant[constant1]{value:1} -&gt; node1;
constant1 -&gt; node2;
</code></pre>
      <h3>
       全连接语法
      </h3>
      <p>
       在图形语言中，从端口连线到端口是很自然的一件事。但是在文本语言中，如果每次连接都显式指定端口，就会很繁琐。在 MDL 语言和
       <code>
        .lig.json
       </code>
       的语法中都是显式指定端口的，因为这样程序解析起来比较容易，但就苦了用户们（当然这两个语言本来也不是直接面向用户的）。Ligral 提供了全连接语法，只要上下游模块之间输出和输入端口一一对应，就可以之间连接而无需指定端口，这在单输入输出节点（最常见的情形）之间连接尤为方便。比如上面的代码
       <code>
        constant1 -&gt; node2
       </code>
       就没有指定端口，Ligral 自动将对应的端口一一连接。
      </p>
      <h3>
       自动装箱
      </h3>
      <p>
       在图形语言中引入一个常数，就拖入一个常数模块，但在文本语言中写
       <code>
        Constant{value:1}
       </code>
       就显得过于厚重。为此，Ligral 提供了一个自动装箱的语法，在连接语句中识别到数字的就会自动将数字装箱成一个常数模块，从而简化语句为
       <code>
        1 -&gt; node1
       </code>
       。
      </p>
      <h3>
       操作符
      </h3>
      <p>
       在图形语言中，双目运算是通过运算模块实现的，如果“直译”成 Ligral 语言就是：
      </p>
      <pre><code>(1, 1) -&gt; Calculator{type: '+'};
</code></pre>
      <p>
       注意这里使用了自动装箱，但语句还是略显繁琐。Ligral 提供了一系列操作符，并在识别到操作符时自动构建
       <code>
        Calculator
       </code>
       模块，将语句简化为
       <code>
        1+1
       </code>
       。
      </p>
      <h3>
       空节点
      </h3>
      <p>
       图形语言的优势在于能表达错综复杂的关系，笔即二维图形的表达能力远超过一维（文字就是一种一维的表达）。但成也萧何，败也萧何，正因表达能力太强，才导致工程文件难以维护，因为人的思维其实是线性的。
      </p>
      <p>
       在 Ligral 中，为了解决表达能力的问题，并且在保持语法简洁性，引入了空节点这一概念。空节点实际上是一个模块，直接转发输入到输出。这允许用户在一个线性的连接任意位置打上标记，并在另一个语句（甚至同一个语句）中引用。例如表示一个环：
      </p>
      <pre><code> ╭───╮           ┌─────┐          ╭───╮
 │ u ├───►(x)───►│ 1/s ├────┬────►│ x │
 ╰───╯     ▲-    └─────┘    │     ╰───╯
           │    ┌───┐       │
           └────┤ k │◄──────┘
                └───┘
</code></pre>
      <p>
       利用空节点来标记很轻松就能用 Ligral 表达：
      </p>
      <pre><code>u-k*x -&gt; Integrator -&gt; x;
</code></pre>
      <p>
       空节点在 Ligral 中非常常见，因此我们简化了空节点的声明语法。完整的声明应该是
       <code>
        Node[x]
       </code>
       ，但在解释器里，凡是出现没有声明过的标识符一律处理成空节点。但这么做有一个问题，在于当用户不小心拼错标识符名称，或者本该声明标识符但是没有声明，该标识符会被识别成一个新的空节点，从而报出意料之外的错误（通常是节点未连接）。这个问题是需要解决的，但目前没有很好的处理办法。
      </p>
      <h3>
       矩阵构建语法
      </h3>
      <p>
       在 Simulink 中，从标量构建矩阵是由
       <code>
        Mux
       </code>
       模块实现的；反之，从矩阵解构到标量是通过
       <code>
        DeMux
       </code>
       模块。Ligral 与之对应的模块是
       <code>
        Stack
       </code>
       系列和
       <code>
        Split
       </code>
       系列（Ligral 对行和列两个方向作了区分）。目前最后一步采用
       <code>
        Split
       </code>
       而非
       <code>
        VSplit
       </code>
       的原因是标量和矩阵尚未统一，
       <code>
        VSplit
       </code>
       分解后的数据仍是矩阵而非标量。
      </p>
      <pre><code>(1, 2) -&gt; HStack -&gt; row1;
(3, 4) -&gt; HStack -&gt; row2;
(row1, row2) -&gt; VStack -&gt; mat;

mat -&gt; HSplit -&gt; (col1, col2);
col1 -&gt; Split -&gt; (item11, item21);
col2 -&gt; Split -&gt; (item12, item22);
</code></pre>
      <p>
       但在文本语言中，矩阵的操作还能再简化一些。
      </p>
      <pre><code>[1, 2; 3, 4] -&gt; mat -&gt; [item11, item12; item21, item22];
</code></pre>
      <p>
       这样更符合文本语言使用者的使用习惯。
      </p>
     </article>
    </div>
    <!-- Sidebar -->
    <aside class="col-sm-4">
     <div class="sidebar-box">
      <h4>
       目录
      </h4>
      <div class="list-group list-group-root">
       <a class="list-group-item" href="/ligral/quick-start.html">
        快速开始
       </a>
       <a class="list-group-item" href="/ligral/user-guide/index.html">
        用户文档
       </a>
       <div class="list-group">
        <a class="list-group-item" href="/ligral/user-guide/terms.html">
         术语定义
        </a>
        <a class="list-group-item" href="/ligral/user-guide/config.html">
         设置语句
        </a>
        <a class="list-group-item" href="/ligral/user-guide/const.html">
         声明常量
        </a>
        <a class="list-group-item" href="/ligral/user-guide/node.html">
         声明节点
        </a>
        <a class="list-group-item" href="/ligral/user-guide/link.html">
         节点连接
        </a>
        <a class="list-group-item" href="/ligral/user-guide/matrix.html">
         矩阵运算
        </a>
        <a class="list-group-item" href="/ligral/user-guide/route.html">
         路由类型
        </a>
        <a class="list-group-item" href="/ligral/user-guide/signature.html">
         接口签名
        </a>
        <a class="list-group-item" href="/ligral/user-guide/import.html">
         引用依赖
        </a>
       </div>
       <a class="list-group-item" href="/ligral/dev-guide/index.html">
        开发文档
       </a>
       <div class="list-group">
        <a class="list-group-item active" href="/ligral/dev-guide/syntax.html">
         语法设计
        </a>
        <a class="list-group-item" href="/ligral/dev-guide/interpreter.html">
         解释器
        </a>
        <a class="list-group-item" href="/ligral/dev-guide/component.html">
         模块组件
        </a>
        <a class="list-group-item" href="/ligral/dev-guide/simulation.html">
         问题抽象
        </a>
        <a class="list-group-item" href="/ligral/dev-guide/tools.html">
         工具箱
        </a>
       </div>
       <a class="list-group-item" href="/ligral/interface/index.html">
        接口定义
       </a>
       <div class="list-group">
        <a class="list-group-item" href="/ligral/interface/model.html">
         模块接口
        </a>
        <a class="list-group-item" href="/ligral/interface/protocol.html">
         数据接口
        </a>
       </div>
      </div>
     </div>
     <div class="sidebar-box sidebar-box-bg">
      <h4>
       关于我们
      </h4>
      <p>
       我们是一群有志于突破工业软件封锁、具有开源精神的开发者。本项目旨在替代 Simulink 进行仿真，通过与框图等效的文本语言描述仿真对象，并解释/编译而后求解。
       <a class="readmore" href="https://gitee.com/junruoyu-zheng/ligral/wikis" target="_blank">
        更多 »
       </a>
      </p>
     </div>
     <div class="sidebar-box">
      <h4>
       仓库链接
      </h4>
      <ul>
       <li>
        <a href="https://gitee.com/junruoyu-zheng/ligral" target="_blank" title="Gitee">
         Gitee 仓库
        </a>
       </li>
       <li>
        <a href="https://github.com/JRY-Zheng/ligral" target="_blank" title="GitHub">
         GitHub 仓库
        </a>
       </li>
      </ul>
     </div>
    </aside>
   </div>
  </main>
  <!-- Footer -->
  <footer class="footer">
   <div class="footer-lists">
    <div class="container">
     <div class="row">
      <div class="col-sm">
       <ul>
        <li>
         <h4>
          联系我们
         </h4>
        </li>
        <li>
         <a href="mailto:zhengjry@outlook.com">
          给我们发邮件
         </a>
        </li>
        <li>
         <a href="https://www.zhihu.com/people/LostFish" target="_blank">
          来知乎关注我
         </a>
        </li>
        <li>
         <a href="https://web.okjike.com/u/105ad022-f646-48c0-8236-6007ee5179c5" target="_blank">
          来即刻关注我
         </a>
        </li>
       </ul>
      </div>
      <div class="col-sm">
       <ul>
        <li>
         <h4>
          代码仓库
         </h4>
        </li>
        <li>
         <a href="https://gitee.com/junruoyu-zheng/ligral" target="_blank">
          Gitee 仓库
         </a>
        </li>
        <li>
         <a href="https://github.com/JRY-Zheng/ligral" target="_blank">
          GitHub 仓库
         </a>
        </li>
       </ul>
      </div>
      <div class="col-sm">
       <ul>
        <li>
         <h4>
          合作伙伴
         </h4>
        </li>
        <li>
         <a href="http://pyminer.com" target="_blank">
          PyMiner 官网
         </a>
        </li>
        <li>
         <a href="https://gitee.com/py2cn/pyminer" target="_blank">
          PyMiner 仓库地址
         </a>
        </li>
       </ul>
      </div>
      <div class="col-sm">
       <h4>
        致谢
       </h4>
       <p>
        Ligral 的开发得到了很多帮助，特在此致谢！感谢我的单位对创新的鼓励；感谢我的导师 James 对数值积分的指导；感谢 Gitee 对项目的支持，在刚开源不久就为我推荐；感谢 PyMiner 开发团队对我的鼓励和支持！
       </p>
       <p class="social-icons">
        <a href="https://gitee.com/junruoyu-zheng/ligral/stargazers" style="text-decoration: none;" target="_blank">
         <img alt="star" src="https://gitee.com/junruoyu-zheng/ligral/badge/star.svg?theme=dark"/>
        </a>
        <a href="https://www.zhihu.com/people/LostFish" target="_blank">
         <i class="fab fa-zhihu fa-2x zhihu-icon">
         </i>
        </a>
       </p>
      </div>
     </div>
    </div>
   </div>
   <div class="footer-bottom">
    <p class="text-center">
     Copyright © 2021. Ligral All rights reserved. 梨果科技版权所有 © 2021
    </p>
    <p class="text-center">
     <a href="#">
      <i class="fa fa-arrow-up">
      </i>
      回到顶部
     </a>
    </p>
   </div>
  </footer>
  <!-- Bootcamp JavaScript -->
  <!-- jQuery first, then Popper.js, then Bootstrap JS -->
  <script src="/ligral/js/jquery-3.2.1.slim.min.js">
  </script>
  <script src="/ligral/js/popper.min.js">
  </script>
  <script src="/ligral/js/bootstrap.min.js">
  </script>
  <script src="/ligral/js/TweenMax.min.js">
  </script>
  <script src="/ligral/js/rolling.js">
  </script>
 </body>
</html>